package com.quick.android.handler.http;

import android.content.Context;

import com.android.volley.AuthFailureError;
import com.android.volley.DefaultRetryPolicy;
import com.android.volley.Request.Method;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
import com.quick.android.handler.http.impl.OnResponseListener;
import com.quick.android.handler.http.request.DownloadRequest;
import com.quick.android.handler.http.request.GsonRequest;
import com.quick.android.handler.http.stack.OkHttpStack;
import com.quick.android.utils.FileUtils;
import com.squareup.okhttp.OkHttpClient;

import org.json.JSONObject;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.util.Map;

public class HttpHandler {
    private static HttpHandler instance;
    private RequestQueue mRequestQueue;
    private OkHttpStack mOkHttpStack;
    private OkHttpClient mOkHttpClient;

    public static HttpHandler getInstance(Context context) {
        if (instance == null) {
            instance = new HttpHandler(context);
        }
        return instance;
    }

    private HttpHandler(Context context) {
        mOkHttpClient = new OkHttpClient();
        mOkHttpStack = new OkHttpStack(mOkHttpClient);
        mRequestQueue = Volley.newRequestQueue(context.getApplicationContext(), mOkHttpStack);
    }

    /**
     * get方式获取数据，数据经过gson转化为javaBean,在回调中获取
     *
     * @param context
     * @param url
     * @param params
     * @param clazz
     * @param callback
     */
    public <T> void getGsonData(Context context, String url,
                                Map<String, String> params, Class<T> clazz,
                                final OnResponseListener<T> callback) {
        getGsonData(context, url, null, params, clazz, callback);
    }

    /**
     * get方式获取数据，数据经过gson转化为javaBean,在回调中获取
     *
     * @param context
     * @param url
     * @param header
     * @param params
     * @param clazz
     * @param callback
     */
    public <T> void getGsonData(Context context, String url,
                                Map<String, String> header, Map<String, String> params,
                                Class<T> clazz, final OnResponseListener<T> callback) {
        httpGsonData(context, Method.GET, url, header, params, clazz, callback);
    }

    /**
     * 发送get请求,返回的数据为String,需要自行处理
     *
     * @param context
     * @param url
     * @param callback
     */
    public void get(Context context, String url,
                    final OnResponseListener<String> callback) {
        get(context, url, null, callback);
    }

    /**
     * 发送get请求,返回的数据为String,需要自行处理
     *
     * @param context
     * @param url
     * @param header
     * @param callback
     */
    public void get(Context context, String url,
                    final Map<String, String> header,
                    final OnResponseListener<String> callback) {
        StringRequest request = new StringRequest(Method.GET, url,
                new Response.Listener<String>() {
                    @Override
                    public void onResponse(String response) {
                        callback.onSuccess(response);
                    }
                }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                callback.onFailure(error.getMessage());
            }
        }) {

            @Override
            public Map<String, String> getHeaders() throws AuthFailureError {
                return header;
            }

        };
        request.setRetryPolicy(new DefaultRetryPolicy(20 * 1000, 1, 1.0f));
        request.setTag(context);
        mRequestQueue.add(request);
    }

    /**
     * post请求数据，返回数据以javaBean格式返回
     *
     * @param context
     * @param url
     * @param params
     * @param clazz
     * @param callback
     */
    public <T> void postGsonData(Context context, String url,
                                 final Map<String, String> params, Class<T> clazz,
                                 final OnResponseListener<T> callback) {
        postGsonData(context, url, null, params, clazz, callback);
    }

    /**
     * post请求数据，返回数据以javaBean格式返回
     *
     * @param context
     * @param url
     * @param header
     * @param params
     * @param clazz
     * @param callback
     */
    public <T> void postGsonData(Context context, String url,
                                 final Map<String, String> header, final Map<String, String> params,
                                 Class<T> clazz, final OnResponseListener<T> callback) {
        httpGsonData(context, Method.POST, url, header, params, clazz, callback);
    }

    /**
     * post请求数据，返回String数据
     *
     * @param context
     * @param url
     * @param params
     * @param callback
     */
    public void post(Context context, String url,
                     final Map<String, String> params,
                     final OnResponseListener<String> callback) {
        post(context, url, null, params, callback);
    }

    /**
     * 发送post请求
     */
    public void post(Context context, String url,
                     final Map<String, String> header, final Map<String, String> params,
                     final OnResponseListener<String> callback) {
        StringRequest request = new StringRequest(Method.POST, url,
                new Response.Listener<String>() {
                    @Override
                    public void onResponse(String response) {
                        callback.onSuccess(response);
                    }
                }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                callback.onFailure(error.getMessage());
            }
        }) {

            @Override
            public Map<String, String> getHeaders() throws AuthFailureError {
                return header;
            }

            @Override
            protected Map<String, String> getParams() throws AuthFailureError {
                return params;
            }
        };
        request.setRetryPolicy(new DefaultRetryPolicy(10 * 1000, 0, 1.0f));
        request.setTag(context);
        mRequestQueue.add(request);
    }

    /**
     * 发送文件上传请求（适合小文件）
     */
    public void upload(Context context, String url, Map<String, String> params,
                       Map<String, File> files,
                       final OnResponseListener<JSONObject> callBack) {
        upload(context, url, null, params, files, callBack);
    }

    /**
     * 发送文件上传请求（适合小文件）
     */
    public void upload(Context context, String url,
                       final Map<String, String> header, final Map<String, String> params,
                       final Map<String, File> files,
                       final OnResponseListener<JSONObject> callBack) {

    }

    /**
     * 文件下载（适合小文件）
     *
     * @param context
     * @param url
     * @param path
     * @param callBack
     */
    public void download(Context context, String url, final String path,
                         final OnResponseListener<File> callBack) {
        DownloadRequest request = new DownloadRequest(url, path,
                new Response.Listener<byte[]>() {
                    @Override
                    public void onResponse(byte[] response) {
                        File file = saveFileFromBytes(path, response);
                        callBack.onSuccess(file);
                    }
                }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                callBack.onFailure(error.getMessage());
            }
        });
        request.setTag(context);
        mRequestQueue.add(request);
    }

    private File saveFileFromBytes(String path, byte[] bytes) {
        File file = null;
        if (bytes != null) {
            file = new File(path);
            InputStream stream = new ByteArrayInputStream(bytes);
            FileUtils.writeFile(file, stream);
        }
        return file;
    }

    /**
     * 请求数据，以javaBean格式返回
     *
     * @param context
     * @param type
     * @param url
     * @param header
     * @param params
     * @param clazz
     * @param callback
     */
    private <T> void httpGsonData(Context context, int type, String url,
                                  final Map<String, String> header, final Map<String, String> params,
                                  Class<T> clazz, final OnResponseListener<T> callback) {
        GsonRequest<T> request = new GsonRequest<T>(type, url, clazz, header,
                params, new Response.Listener<T>() {

            @Override
            public void onResponse(T response) {
                callback.onSuccess(response);
            }
        }, new Response.ErrorListener() {

            @Override
            public void onErrorResponse(VolleyError error) {
                callback.onFailure(error.getMessage());
            }
        });

        request.setRetryPolicy(new DefaultRetryPolicy(20 * 1000, 1, 1.0f));
        request.setTag(context);
        mRequestQueue.add(request);
    }

    /**
     * 取消与context关联的所有请求
     */
    public void cancelAllRequest(Context context) {
        mRequestQueue.cancelAll(context);
    }
}
